import ply.lex as lex

# List of token names.   This is always required
tokens = (
    'NUMBER',
    # A code
    'AT',
    # C code
    'PLUS',
    'MINUS',
    'AND',
    'OR',
    'EQUAL',
    'NOT',
    'SEMICOLON',
    # label
    'LPAREN',
    'RPAREN',
    # label or variable
    'LABEL',
    # ID A D M
    'ID',
    # JMP
    'JMP',
)


# Regular expression rules for simple tokens
t_AT = r'\@'
t_PLUS = r'\+'
t_MINUS = r'-'
t_AND = r'&'
t_OR = r'\|'
t_EQUAL = r'='
t_NOT = r'!'
t_LPAREN = r'\('
t_RPAREN = r'\)'
t_SEMICOLON = r';'


def t_NUMBER(t):
    r'\d+'
    t.value = int(t.value)
    return t


def t_newline(t):
    r'\n+'
    t.lexer.lineno += len(t.value)


t_ignore = r' '
t_ignore_comment = r'//.*'

# must before label parser


def t_JMP(t):
    r'J(GT|EQ|GE|LT|NE|LE|MP)'
    t.type = 'JMP'
    return t


def t_LABEL(t):
    r'[a-zA-Z][a-zA-Z_0-9\.$]*'
    t.type = 'LABEL'
    value = ''.join(sorted(t.value))
    if value in ['A', 'M', 'D','AM', 'AD', 'DM', 'ADM']:
        t.type = 'ID'
    return t


# Error handling rule


def t_error(t):
    print("Illegal character '%s'" % t.value[0])
    t.lexer.skip(1)


# Build the lexer
lexer = lex.lex()

if __name__ == "__main__":
    s = '''
    @LABEL1
    // Hello
    MD=A+M;JGE
    (LABEL1)
    -1;JMP
    @ARG
    '''

    lexer.input(s)

    while True:
        tok = lexer.token()
        if not tok:
            break

        print(tok)
